﻿using System;
using System.Net;
using System.Runtime.InteropServices;

namespace PingInfo.Helpers
{
    public class PingWindowsApi
    {

        private IcmpOptions _oIcmpOptions;
        public IcmpEchoReply IcmpReply;

        [DllImport("iphlpapi.dll", SetLastError = true)]
        private static extern IntPtr IcmpCreateFile();
        [DllImport("iphlpapi.dll", SetLastError = true)]
        private static extern bool IcmpCloseHandle(IntPtr handle);
        [DllImport("iphlpapi.dll", SetLastError = true)]
        private static extern int IcmpSendEcho(IntPtr icmpHandle, uint destinationAddress, string requestData, int requestSize, ref IcmpOptions requestOptions, ref IcmpEchoReply replyBuffer, int replySize, int timeout);
        public bool Ping(IPAddress ip, int timeout = 1500, int size = 32)
        {
            string sData = string.Empty;
            var icmpHandle = IcmpCreateFile();
            uint iIp = BitConverter.ToUInt32(ip.GetAddressBytes(), 0);
            const string sTemp = "x";
            for (int i = 0; i < size; i++)
            {
                sData += sTemp;
            }
            _oIcmpOptions.Ttl = 255;
            int iReplies = IcmpSendEcho(icmpHandle, iIp, sData, sData.Length, ref _oIcmpOptions, ref IcmpReply, Marshal.SizeOf(IcmpReply), timeout);
            IcmpCloseHandle(icmpHandle);
            return iReplies == 1 && IcmpReply.DataSize > 0;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct IcmpOptions
        {
            public byte Ttl;
            private readonly byte Tos;
            private readonly byte Flags;
            private readonly byte OptionsSize;
            private readonly IntPtr OptionsData;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct IcmpEchoReply
        {
            private readonly int Address;
            private readonly int Status;
            public readonly int RoundTripTime;
            public readonly short DataSize;
            private readonly short Reserved;
            private readonly IntPtr DataPtr;
            public readonly IcmpOptions Options;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 250)]
            private readonly string Data;
        }
    }
}
